namespace DotNetNuke.Common.Utilities
{
    using DotNetNuke.Framework;
    using DotNetNuke.Services.Exceptions;
    using Microsoft.VisualBasic;
    using Microsoft.VisualBasic.CompilerServices;
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Data;
    using System.IO;
    using System.Reflection;
    using System.Runtime.CompilerServices;
    using System.Text;
    using System.Xml;
    using System.Xml.Serialization;

    /// -----------------------------------------------------------------------------
    /// Namespace: DotNetNuke.Common.Utilities
    /// Project	 : DotNetNuke
    /// Class	 : CBO
    /// -----------------------------------------------------------------------------
    /// <summary>
    /// Library responsible for building business objects from DataReaders
    /// </summary>
    /// <remarks>
    /// </remarks>
    /// <history>
    /// [cnurse]	10/10/2005	Documented
    /// </history>
    /// -----------------------------------------------------------------------------
    public class CBO
    {
        /// -----------------------------------------------------------------------------
        /// <summary>
        /// Shared method that returns a Clone (copy) of an object
        /// </summary>
        /// <param name="ObjectToClone">The object to be cloned</param>
        /// <returns>The resulting object</returns>
        /// <remarks></remarks>
        /// <history>
        /// [cnurse]	10/10/2005	Documented
        /// </history>
        /// -----------------------------------------------------------------------------
        public static object CloneObject(object ObjectToClone)
        {
            object CloneObject;
            try
            {
                object newObject = RuntimeHelpers.GetObjectValue(Reflection.CreateObject(ObjectToClone.GetType().AssemblyQualifiedName, ObjectToClone.GetType().AssemblyQualifiedName));
                ArrayList props = GetPropertyInfo(newObject.GetType());
                int i = 0;
                int refIntHelperL0 = GetPropertyInfo(ObjectToClone.GetType()).Count - 1;
                for (i = 0; i <= refIntHelperL0; i++)
                {
                    PropertyInfo p = (PropertyInfo) GetPropertyInfo(ObjectToClone.GetType())[i];
                    Type ICloneType = p.PropertyType.GetInterface("ICloneable", true);
                    if (((PropertyInfo) props[i]).CanWrite)
                    {
                        if (ICloneType != null)
                        {
                            ICloneable IClone = (ICloneable) p.GetValue(RuntimeHelpers.GetObjectValue(ObjectToClone), null);
                            ((PropertyInfo) props[i]).SetValue(RuntimeHelpers.GetObjectValue(newObject), RuntimeHelpers.GetObjectValue(IClone.Clone()), null);
                        }
                        else
                        {
                            ((PropertyInfo) props[i]).SetValue(RuntimeHelpers.GetObjectValue(newObject), RuntimeHelpers.GetObjectValue(p.GetValue(RuntimeHelpers.GetObjectValue(ObjectToClone), null)), null);
                        }
                        if (p.PropertyType.GetInterface("IEnumerable", true) != null)
                        {
                            IEnumerable IEnum = (IEnumerable) p.GetValue(RuntimeHelpers.GetObjectValue(ObjectToClone), null);
                            Type IListType = ((PropertyInfo) props[i]).PropertyType.GetInterface("IList", true);
                            Type IDicType = ((PropertyInfo) props[i]).PropertyType.GetInterface("IDictionary", true);
                            int j = 0;
                            if (IListType != null)
                            {
                                IEnumerator refObjectHelperL0=null;
                                IList list = (IList) ((PropertyInfo) props[i]).GetValue(RuntimeHelpers.GetObjectValue(newObject), null);
                                try
                                {
                                    refObjectHelperL0 = IEnum.GetEnumerator();
                                    while (refObjectHelperL0.MoveNext())
                                    {
                                        object obj = RuntimeHelpers.GetObjectValue(refObjectHelperL0.Current);
                                        if (obj.GetType().GetInterface("ICloneable", true) != null)
                                        {
                                            list[j] = RuntimeHelpers.GetObjectValue(((ICloneable) obj).Clone());
                                        }
                                        j++;
                                    }
                                }
                                finally
                                {
                                    if (refObjectHelperL0 is IDisposable)
                                    {
                                        (refObjectHelperL0 as IDisposable).Dispose();
                                    }
                                }
                            }
                            else if (IDicType != null)
                            {
                                IEnumerator refObjectHelperL1=null;
                                IDictionary dic = (IDictionary) ((PropertyInfo) props[i]).GetValue(RuntimeHelpers.GetObjectValue(newObject), null);
                                j = 0;
                                try
                                {
                                    refObjectHelperL1 = IEnum.GetEnumerator();
                                    while (refObjectHelperL1.MoveNext())
                                    {
                                        DictionaryEntry de = (DictionaryEntry) refObjectHelperL1.Current;
                                        if (de.Value.GetType().GetInterface("ICloneable", true) != null)
                                        {
                                            dic[RuntimeHelpers.GetObjectValue(de.Key)] = RuntimeHelpers.GetObjectValue(((ICloneable) de.Value).Clone());
                                        }
                                        j++;
                                    }
                                }
                                finally
                                {
                                    if (refObjectHelperL1 is IDisposable)
                                    {
                                        (refObjectHelperL1 as IDisposable).Dispose();
                                    }
                                }
                            }
                        }
                    }
                }
                CloneObject = newObject;
            }
            catch (Exception exception1)
            {
                
                Exception exc = exception1;
                DotNetNuke.Services.Exceptions.Exceptions.LogException(exc);
                CloneObject = null;
                
                return CloneObject;
                
            }
            return CloneObject;
        }

        /// -----------------------------------------------------------------------------
        /// <summary>
        /// Generic version of CreateObject creates an object of a specified type from the 
        /// provided DataReader
        /// </summary>
        /// <typeparam name="T">The type of the business object</typeparam>
        /// <param name="dr">The DataReader</param>
        /// <returns>The custom business object</returns>
        /// <remarks></remarks>
        /// <history>
        /// [cnurse]	10/10/2005	Created
        /// </history>
        /// -----------------------------------------------------------------------------
        private static T CreateObject<T>(IDataReader dr)
        {
            Type objPropertyType = null;
            T objObject = Activator.CreateInstance<T>();
            ArrayList objProperties = GetPropertyInfo(objObject.GetType());
            int[] arrOrdinals = GetOrdinals(objProperties, dr);
            int refIntHelperL0 = objProperties.Count - 1;
            for (int intProperty = 0; intProperty <= refIntHelperL0; intProperty++)
            {
                PropertyInfo objPropertyInfo = (PropertyInfo) objProperties[intProperty];
                if (objPropertyInfo.CanWrite)
                {
                    object objValue = RuntimeHelpers.GetObjectValue(Null.SetNull(objPropertyInfo));
                    if (arrOrdinals[intProperty] != -1)
                    {
                        if (Information.IsDBNull(RuntimeHelpers.GetObjectValue(dr.GetValue(arrOrdinals[intProperty]))))
                        {
                            objPropertyInfo.SetValue(objObject, RuntimeHelpers.GetObjectValue(objValue), null);
                        }
                        else
                        {
                            try
                            {
                                objPropertyInfo.SetValue(objObject, RuntimeHelpers.GetObjectValue(dr.GetValue(arrOrdinals[intProperty])), null);
                            }
                            catch (Exception exception1)
                            {
                                
                                try
                                {
                                    objPropertyType = objPropertyInfo.PropertyType;
                                    if (objPropertyType.BaseType.Equals(typeof(Enum)))
                                    {
                                        if (Versioned.IsNumeric(RuntimeHelpers.GetObjectValue(dr.GetValue(arrOrdinals[intProperty]))))
                                        {
                                            ((PropertyInfo) objProperties[intProperty]).SetValue(objObject, RuntimeHelpers.GetObjectValue(Enum.ToObject(objPropertyType, Convert.ToInt32(RuntimeHelpers.GetObjectValue(dr.GetValue(arrOrdinals[intProperty]))))), null);
                                        }
                                        else
                                        {
                                            ((PropertyInfo) objProperties[intProperty]).SetValue(objObject, RuntimeHelpers.GetObjectValue(Enum.ToObject(objPropertyType, RuntimeHelpers.GetObjectValue(dr.GetValue(arrOrdinals[intProperty])))), null);
                                        }
                                    }
                                    else
                                    {
                                        objPropertyInfo.SetValue(objObject, RuntimeHelpers.GetObjectValue(Convert.ChangeType(RuntimeHelpers.GetObjectValue(dr.GetValue(arrOrdinals[intProperty])), objPropertyType)), null);
                                    }
                                }
                                catch (Exception exception2)
                                {
                                    ProjectData.SetProjectError(exception2);
                                    objPropertyInfo.SetValue(objObject, RuntimeHelpers.GetObjectValue(Convert.ChangeType(RuntimeHelpers.GetObjectValue(dr.GetValue(arrOrdinals[intProperty])), objPropertyType)), null);
                                    
                                }
                                
                            }
                        }
                    }
                }
            }
            return objObject;
        }

        /// -----------------------------------------------------------------------------
        /// <summary>
        /// Creates an object of a specified type from the provided DataReader
        /// </summary>
        /// <param name="objType">The type of the object</param>
        /// <param name="dr">The DataReader</param>
        /// <returns>The custom business object</returns>
        /// <remarks></remarks>
        /// <history>
        /// [cnurse]	10/10/2005	Documented
        /// </history>
        /// -----------------------------------------------------------------------------
        private static object CreateObject(Type objType, IDataReader dr)
        {
            Type objPropertyType = null;
            object objObject = RuntimeHelpers.GetObjectValue(Activator.CreateInstance(objType));
            ArrayList objProperties = GetPropertyInfo(objType);
            int[] arrOrdinals = GetOrdinals(objProperties, dr);
            int refIntHelperL0 = objProperties.Count - 1;
            for (int intProperty = 0; intProperty <= refIntHelperL0; intProperty++)
            {
                PropertyInfo objPropertyInfo = (PropertyInfo) objProperties[intProperty];
                if (objPropertyInfo.CanWrite)
                {
                    object objValue = RuntimeHelpers.GetObjectValue(Null.SetNull(objPropertyInfo));
                    if (arrOrdinals[intProperty] != -1)
                    {
                        if (Information.IsDBNull(RuntimeHelpers.GetObjectValue(dr.GetValue(arrOrdinals[intProperty]))))
                        {
                            objPropertyInfo.SetValue(RuntimeHelpers.GetObjectValue(objObject), RuntimeHelpers.GetObjectValue(objValue), null);
                        }
                        else
                        {
                            try
                            {
                                objPropertyInfo.SetValue(RuntimeHelpers.GetObjectValue(objObject), RuntimeHelpers.GetObjectValue(dr.GetValue(arrOrdinals[intProperty])), null);
                            }
                            catch (Exception exception1)
                            {
                                
                                try
                                {
                                    objPropertyType = objPropertyInfo.PropertyType;
                                    if (objPropertyType.BaseType.Equals(typeof(Enum)))
                                    {
                                        if (Versioned.IsNumeric(RuntimeHelpers.GetObjectValue(dr.GetValue(arrOrdinals[intProperty]))))
                                        {
                                            ((PropertyInfo) objProperties[intProperty]).SetValue(RuntimeHelpers.GetObjectValue(objObject), RuntimeHelpers.GetObjectValue(Enum.ToObject(objPropertyType, Convert.ToInt32(RuntimeHelpers.GetObjectValue(dr.GetValue(arrOrdinals[intProperty]))))), null);
                                        }
                                        else
                                        {
                                            ((PropertyInfo) objProperties[intProperty]).SetValue(RuntimeHelpers.GetObjectValue(objObject), RuntimeHelpers.GetObjectValue(Enum.ToObject(objPropertyType, RuntimeHelpers.GetObjectValue(dr.GetValue(arrOrdinals[intProperty])))), null);
                                        }
                                    }
                                    else
                                    {
                                        objPropertyInfo.SetValue(RuntimeHelpers.GetObjectValue(objObject), RuntimeHelpers.GetObjectValue(Convert.ChangeType(RuntimeHelpers.GetObjectValue(dr.GetValue(arrOrdinals[intProperty])), objPropertyType)), null);
                                    }
                                }
                                catch (Exception exception2)
                                {
                                    ProjectData.SetProjectError(exception2);
                                    objPropertyInfo.SetValue(RuntimeHelpers.GetObjectValue(objObject), RuntimeHelpers.GetObjectValue(Convert.ChangeType(RuntimeHelpers.GetObjectValue(dr.GetValue(arrOrdinals[intProperty])), objPropertyType)), null);
                                    
                                }
                                
                            }
                        }
                    }
                }
            }
            return objObject;
        }

        /// -----------------------------------------------------------------------------
        /// <summary>
        /// Generic version of FillCollection fills a List custom business object of a specified type 
        /// from the supplied DataReader
        /// </summary>
        /// <typeparam name="T">The type of the business object</typeparam>
        /// <param name="dr">The IDataReader to use to fill the object</param>
        /// <returns>A List of custom business objects</returns>
        /// <remarks></remarks>
        /// <history>
        /// [cnurse]	10/10/2005	Created
        /// </history>
        /// -----------------------------------------------------------------------------
        public static List<T> FillCollection<T>(IDataReader dr)
        {
            List<T> objFillCollection = new List<T>();
            while (dr.Read())
            {
                T objFillObject = CreateObject<T>(dr);
                objFillCollection.Add(objFillObject);
            }
            if (dr != null)
            {
                dr.Close();
            }
            return objFillCollection;
        }

        /// -----------------------------------------------------------------------------
        /// <summary>
        /// Generic version of FillCollection fills a provided IList with custom business 
        /// objects of a specified type from the supplied DataReader
        /// </summary>
        /// <typeparam name="T">The type of the business object</typeparam>
        /// <param name="dr">The IDataReader to use to fill the object</param>
        /// <param name="objToFill">The IList to fill</param>
        /// <returns>An IList of custom business objects</returns>
        /// <remarks></remarks>
        /// <history>
        /// [cnurse]	10/10/2005	Created
        /// </history>
        /// -----------------------------------------------------------------------------
        public static IList<T> FillCollection<T>(IDataReader dr, ref IList<T> objToFill)
        {
            while (dr.Read())
            {
                T objFillObject = CreateObject<T>(dr);
                objToFill.Add(objFillObject);
            }
            if (dr != null)
            {
                dr.Close();
            }
            return objToFill;
        }

        /// -----------------------------------------------------------------------------
        /// <summary>
        /// Fills an ArrayList with custom business objects of a specified type from the supplied 
        /// DataReader
        /// </summary>
        /// <param name="dr">The IDataReader to use to fill the object</param>
        /// <param name="objType">The type of the object</param>
        /// <returns>An ArrayList of custom business objects</returns>
        /// <remarks></remarks>
        /// <history>
        /// [cnurse]	10/10/2005	Documented
        /// </history>
        /// -----------------------------------------------------------------------------
        public static ArrayList FillCollection(IDataReader dr, Type objType)
        {
            ArrayList objFillCollection = new ArrayList();
            while (dr.Read())
            {
                object objFillObject = RuntimeHelpers.GetObjectValue(CreateObject(objType, dr));
                objFillCollection.Add(RuntimeHelpers.GetObjectValue(objFillObject));
            }
            if (dr != null)
            {
                dr.Close();
            }
            return objFillCollection;
        }

        /// -----------------------------------------------------------------------------
        /// <summary>
        /// Fills a provided IList with custom business objects of a specified type from the supplied 
        /// DataReader
        /// </summary>
        /// <param name="dr">The IDataReader to use to fill the object</param>
        /// <param name="objType">The type of the object</param>
        /// <param name="objToFill">The IList to fill</param>
        /// <returns>An IList of custom business objects</returns>
        /// <remarks></remarks>
        /// <history>
        /// [cnurse]	10/10/2005	Documented
        /// </history>
        /// -----------------------------------------------------------------------------
        public static IList FillCollection(IDataReader dr, Type objType, ref IList objToFill)
        {
            while (dr.Read())
            {
                object objFillObject = RuntimeHelpers.GetObjectValue(CreateObject(objType, dr));
                objToFill.Add(RuntimeHelpers.GetObjectValue(objFillObject));
            }
            if (dr != null)
            {
                dr.Close();
            }
            return objToFill;
        }

        /// -----------------------------------------------------------------------------
        /// <summary>
        /// Generic version of FillObject fills a custom business object of a specified type 
        /// from the supplied DataReader
        /// </summary>
        /// <typeparam name="T">The type of the object</typeparam>
        /// <param name="dr">The IDataReader to use to fill the object</param>
        /// <returns>The object</returns>
        /// <remarks>This overloads sets the ManageDataReader parameter to true and calls 
        /// the other overload</remarks>
        /// <history>
        /// [cnurse]	10/10/2005	Created
        /// </history>
        /// -----------------------------------------------------------------------------
        public static T FillObject<T>(IDataReader dr)
        {
            return FillObject<T>(dr, true);
        }

        /// -----------------------------------------------------------------------------
        /// <summary>
        /// Generic version of FillObject fills a custom business object of a specified type 
        /// from the supplied DataReader
        /// </summary>
        /// <typeparam name="T">The type of the object</typeparam>
        /// <param name="dr">The IDataReader to use to fill the object</param>
        /// <param name="ManageDataReader">A boolean that determines whether the DatReader
        /// is managed</param>
        /// <returns>The object</returns>
        /// <remarks>This overloads allows the caller to determine whether the ManageDataReader 
        /// parameter is set</remarks>
        /// <history>
        /// [cnurse]	10/10/2005	Created
        /// </history>
        /// -----------------------------------------------------------------------------
        public static T FillObject<T>(IDataReader dr, bool ManageDataReader)
        {
            bool Continue;
            T objFillObject;
            if (ManageDataReader)
            {
                Continue = false;
                if (dr.Read())
                {
                    Continue = true;
                }
            }
            else
            {
                Continue = true;
            }
            if (Continue)
            {
                objFillObject = CreateObject<T>(dr);
            }
            else
            {
                objFillObject = default(T);
            }
            if (ManageDataReader && (dr != null))
            {
                dr.Close();
            }
            return objFillObject;
        }

        /// -----------------------------------------------------------------------------
        /// <summary>
        /// FillObject fills a custom business object of a specified type from the supplied 
        /// DataReader
        /// </summary>
        /// <param name="dr">The IDataReader to use to fill the object</param>
        /// <param name="objType">The type of the object</param>
        /// <returns>The object</returns>
        /// <remarks>This overloads sets the ManageDataReader parameter to true and calls 
        /// the other overload</remarks>
        /// <history>
        /// [cnurse]	10/10/2005	Documented
        /// </history>
        /// -----------------------------------------------------------------------------
        public static object FillObject(IDataReader dr, Type objType)
        {
            return FillObject(dr, objType, true);
        }

        /// -----------------------------------------------------------------------------
        /// <summary>
        /// FillObject fills a custom business object of a specified type from the supplied 
        /// DataReader
        /// </summary>
        /// <param name="dr">The IDataReader to use to fill the object</param>
        /// <param name="objType">The type of the object</param>
        /// <param name="ManageDataReader">A boolean that determines whether the DatReader
        /// is managed</param>
        /// <returns>The object</returns>
        /// <remarks>This overloads allows the caller to determine whether the ManageDataReader 
        /// parameter is set</remarks>
        /// <history>
        /// [cnurse]	10/10/2005	Documented
        /// </history>
        /// -----------------------------------------------------------------------------
        public static object FillObject(IDataReader dr, Type objType, bool ManageDataReader)
        {
            bool Continue;
            object objFillObject;
            if (ManageDataReader)
            {
                Continue = false;
                if (dr.Read())
                {
                    Continue = true;
                }
            }
            else
            {
                Continue = true;
            }
            if (Continue)
            {
                objFillObject = RuntimeHelpers.GetObjectValue(CreateObject(objType, dr));
            }
            else
            {
                objFillObject = null;
            }
            if (ManageDataReader && (dr != null))
            {
                dr.Close();
            }
            return objFillObject;
        }

        /// -----------------------------------------------------------------------------
        /// <summary>
        /// Gets an ArrList of ordinals (index pointers) that indicate which column in the 
        /// DataReader corresponds to which property in an ArrayList of PropertyInfo objects.
        /// </summary>
        /// <param name="objProperties">The ArrayList of PropertyInfo objects</param>
        /// <param name="dr">The data reader</param>
        /// <returns>An Arralist of ordinals</returns>
        /// <remarks></remarks>
        /// <history>
        /// [cnurse]	10/10/2005	Documented
        /// </history>
        /// -----------------------------------------------------------------------------
        private static int[] GetOrdinals(ArrayList objProperties, IDataReader dr)
        {
            int[] arrOrdinals = new int[objProperties.Count + 1];
            if (dr != null)
            {
                int refIntHelperL0 = objProperties.Count - 1;
                for (int intProperty = 0; intProperty <= refIntHelperL0; intProperty++)
                {
                    arrOrdinals[intProperty] = -1;
                    try
                    {
                        arrOrdinals[intProperty] = dr.GetOrdinal(((PropertyInfo) objProperties[intProperty]).Name);
                    }
                    catch (Exception exception1)
                    {
                        
                        
                    }
                }
            }
            return arrOrdinals;
        }

        /// -----------------------------------------------------------------------------
        /// <summary>
        /// GetPropertyInfo returns an arraylis of properties for the "Type"
        /// </summary>
        /// <param name="objType">The type</param>
        /// <returns>An Arraylist of PropertyInfo objcets representing the properties
        /// of the provided type</returns>
        /// <remarks></remarks>
        /// <history>
        /// [cnurse]	10/10/2005	Documented
        /// </history>
        /// -----------------------------------------------------------------------------
        public static ArrayList GetPropertyInfo(Type objType)
        {
            ArrayList objProperties = (ArrayList) DataCache.GetCache(objType.FullName);
            if (objProperties == null)
            {
                objProperties = new ArrayList();
                foreach (PropertyInfo objProperty in objType.GetProperties())
                {
                    objProperties.Add(objProperty);
                }
                DataCache.SetCache(objType.FullName, objProperties);
            }
            return objProperties;
        }

        /// -----------------------------------------------------------------------------
        /// <summary>
        /// Initializes an object of the specified type
        /// </summary>
        /// <param name="objObject">The object to initialize</param>
        /// <param name="objType">The type of the object</param>
        /// <returns>The initialized object</returns>
        /// <remarks></remarks>
        /// <history>
        /// [cnurse]	10/10/2005	Documented
        /// </history>
        /// -----------------------------------------------------------------------------
        public static object InitializeObject(object objObject, Type objType)
        {
            ArrayList objProperties = GetPropertyInfo(objType);
            int refIntHelperL0 = objProperties.Count - 1;
            for (int intProperty = 0; intProperty <= refIntHelperL0; intProperty++)
            {
                PropertyInfo objPropertyInfo = (PropertyInfo) objProperties[intProperty];
                if (objPropertyInfo.CanWrite)
                {
                    object objValue = RuntimeHelpers.GetObjectValue(Null.SetNull(objPropertyInfo));
                    objPropertyInfo.SetValue(RuntimeHelpers.GetObjectValue(objObject), RuntimeHelpers.GetObjectValue(objValue), null);
                }
            }
            return objObject;
        }

        /// -----------------------------------------------------------------------------
        /// <summary>
        /// Serializes an object as an Xml Document
        /// </summary>
        /// <param name="objObject">The object to serialize</param>
        /// <returns>The serialized object's Xml</returns>
        /// <remarks></remarks>
        /// <history>
        /// [cnurse]	10/10/2005	Documented
        /// </history>
        /// -----------------------------------------------------------------------------
        public static XmlDocument Serialize(object objObject)
        {
            XmlSerializer objXmlSerializer = new XmlSerializer(objObject.GetType());
            StringBuilder objStringBuilder = new StringBuilder();
            TextWriter objTextWriter = new StringWriter(objStringBuilder);
            objXmlSerializer.Serialize(objTextWriter, RuntimeHelpers.GetObjectValue(objObject));
            StringReader objStringReader = new StringReader(objTextWriter.ToString());
            DataSet objDataSet = new DataSet();
            objDataSet.ReadXml(objStringReader);
            XmlDocument xmlSerializedObject = new XmlDocument();
            xmlSerializedObject.LoadXml(objDataSet.GetXml());
            return xmlSerializedObject;
        }
    }
}

